//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<event_center.h>
///	@path	~/src/engine/xcore/
///	@date	2007/11/07
///	@desc	Event processing center.

#pragma once

#include "xeres.h"

#include "lib/utilities/dir_tree.h"

#include "engine/runtime/IEvent.h"

#include <map>
#include <queue>

namespace xeres {

	/// Event Handling Results
	enum HandleEvent
	{
		/// Indicates event is not handled, should be passed to next slot.
		EVENT_UNHANDLED = 0 ,
		/// Indicates event is handled, but for event that specified pass to all slot, this tag is not used.
		EVENT_HANDLED = 1
	};

	/// Event slot, event subscriber will sort to process events in this order
	enum EventSlot
	{
		/// Most top level, for input event translation.
		EVENTSLOT_INPUT = 0 ,
		/// Debug level, for debug functions.
		EVENTSLOT_DEBUG ,			
		/// For applicate hot key.
		EVENTSLOT_APP ,
		/// For engine processing.
		EVENTSLOT_ENGINE ,
		/// For script processing.
		EVENTSLOT_SCRIPT ,
		//
		EVENTSLOT_last
	};

	/// Names response to \ref EventSlot .
	static const wchar_t * EventSlotNames [] =
	{
		_S("input") ,
		_S("debug") ,
		_S("app") ,
		_S("engine") ,
		_S("script")
	};

	typedef int EventID;

#define	INVALID_EVENT_ID		(-1)

	/*!
		\class	EventCenter
		\brief	Register, receive & reflect events.
		\detail
		\par System Events:
		.					-	root holder, not for use.
		input				-	inputs, including input device event.
		message				-	windows messages.
		network				-	network events.
		user				-	for user events.
		<BR>
		\par Special Events:
		input/keyboard		-	keyboard input event.
		input/mouse			-	mouse input event.
		input/device		-	other device input event.
		message/size		-	size change message.
		message/activate	-	windows activate/inactivate message.
		message/paint		-	windows paint message
	*/
	class EventCenter
	{
	protected:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		EventCenter( void );

		/// \dtor
		~EventCenter( void );

		//@}

		/// \name Internal Manipulation
		//@{

		/*!
			\brief		Initialize event center.
		*/
		void Initialize( void );

		/*!
			\brief		Finalize event center.
		*/
		void Finalize( void );

		//@}

	public:

		/// \name Interface Manipulation
		//@{

		/*!
			\brief		Register event in category.
						Notice if we set 'active_all' to true, then no matter if subscriber
						handled the event or not, all subscriber will be called.
						Careful to use this tag if event really wants all subscriber be notified.
		*/
		bool RegisterEvent( const WString& path , RefWeak<IEvent> event , bool active_all );

		/*!
			\brief		Release specific event ( event will no longer active ).
		*/
		bool ReleaseEvent( const WString& path );

		/*!
			\brief		Subscribe specific event.
		*/
		EventID SubscribeEvent( const WString& path , EventSlot slot ,
			function<HandleEvent(void*)> subscriber , function<void(void)> released = NULL );

		//@}

	private:

		// active event

		struct _EventPlug
		{
			int								m_id;
			EventSlot						m_slot;
			function<HandleEvent(void*)>	m_call;
			function<void(void)>			m_released;
		};

		struct _EventNode
		{
			Ref<IEvent>						m_event;
			WString							m_path;
			std::deque< _EventPlug >		m_plugs;
			// status
			bool							m_iterateAllPlug;
			bool							m_spare0[3];
		};

		/*!
			\brief		Callback for event to active itself.
		*/
		static void ActiveCallback( void * data , void * eventParam );

		//@ data

		// category
		dir_tree< _EventNode * >		m_eventTree;
		EventID							m_eventId;
	};

} // namespace xeres
